package com.sea.base.permission

import android.content.Context
import android.content.pm.PackageManager
import android.view.Gravity
import androidx.appcompat.app.AlertDialog
import androidx.core.content.ContextCompat
import androidx.fragment.app.FragmentActivity
import com.sea.base.ext.global.postMainDelayedLifecycle
import com.sea.base.ext.global.throwIfDebug
import com.sea.base.ext.obs.doOnNextResumed
import com.sea.base.ext.view.requireActivity
import com.sea.base.ext.view.showWrapLifecycle
import com.sea.base.ui.isAllGrantedPermission

/**
 * 这是一个权限请求类
 *
 * 借助透明Fragment实现，任意页面发起权限请求
 * 关于部分手机在主动关闭权限的情况下，走权限申请直接返回true ，适配范围过大，需自行处理
 */
class PermissionBox(private val ui: com.sea.base.ui.IUIContext) {

    companion object {
        /**
         * 只是为了提供外部在minSDK过低时提供Lint限制
         * 实际请求权限时，会使用IS_BIG_THAN_SDK_M 进行过滤。低版本不会进入请求权限
         */
        fun with(ui: com.sea.base.ui.IUIContext) = PermissionBox(ui)

        /**
         * 是否同意了某个权限
         */
        fun isGranted(context: Context, perName: String) =
            ContextCompat.checkSelfPermission(context, perName) == PackageManager.PERMISSION_GRANTED

        /**
         * 是否被撤销了权限
         */
        fun isRevoked(activity: FragmentActivity, permission: String) =
            activity.packageManager.isPermissionRevokedByPolicy(permission, activity.packageName)
    }

    private var onAllGrantedCallback: (() -> Unit)? = null
    private val pNames: ArrayList<String> = arrayListOf()
    private val majorPermission: ArrayList<String> = arrayListOf()
    private var transformPermissionName = DefaultPermissionInfo.transformPermissionName
    private var permissionPurpose = DefaultPermissionInfo.permissionPurpose
    private var onPermanentlyRejectCallback: ((
        permanentlyRejectList: List<PermissionBean>,
        grantedList: List<PermissionBean>,
        rejectList: List<PermissionBean>
    ) -> Unit)? = null

    private var onRejectCallback: ((grantedList: List<PermissionBean>, rejectList: List<PermissionBean>) -> Unit)? = null

    private var purposeDialog: AlertDialog? = null

    fun defaultPermanentlyReject() = { permanentlyRejectList: List<PermissionBean>,
                                       grantedList: List<PermissionBean>,
                                       rejectList: List<PermissionBean> ->
        val permissionNames =
            permanentlyRejectList.filter { it.permissionName.isNotEmpty() }
                .map { it.permissionName }
        val stringBuilder = StringBuilder("您拒绝了")
        if (permissionNames.isEmpty()) {
            stringBuilder.append("该")
        } else {
            stringBuilder.append(permissionNames.joinToString("、"))
            if (permissionNames.size != permanentlyRejectList.size) {
                stringBuilder.append("等")
            }
        }
        stringBuilder.append("权限，会导致部分功能不能正常使用，请在权限页面打开对应权限，是否去打开？")
        val alertDialogBuilder = AlertDialog.Builder(ui.requireActivity).setTitle("权限拒绝提示")
            .setMessage(stringBuilder)
            .setCancelable(false)
            .setPositiveButton("去开启") { dialog, _ ->
                PermissionDetailManager.toSettingPermission(ui.requireActivity)
                dialog?.dismiss()
                ui.lifecycle.doOnNextResumed {
                    forceRequest()
                }
            }
            .setNegativeButton("取消") { dialog, _ ->
                dialog?.dismiss()
                onRejectCallback?.invoke(grantedList, permanentlyRejectList + rejectList)
            }
        alertDialogBuilder.create().showWrapLifecycle(ui.lifecycle)
    }

    /**
     * 添加普通权限申请（普通权限拒绝后直接回调拒绝结果，不会再次提醒）
     */
    fun setRequestPermission(vararg pNames: String): PermissionBox {
        this.pNames.clear()
        this.pNames.addAll(pNames)
        return this
    }

    /**
     * 设置必要权限（必要权限如果被拒绝将会提醒开启并跳到设置页）
     * @param onPermanentlyRejectCallback 当完全拒绝时回调，默认弹窗并引导手动打开[defaultPermanentlyReject]
     */
    fun setMajorPermission(
        vararg majorPermission: String,
        onPermanentlyRejectCallback: ((
            permanentlyRejectList: List<PermissionBean>,
            grantedList: List<PermissionBean>,
            rejectList: List<PermissionBean>
        ) -> Unit) = defaultPermanentlyReject()
    ): PermissionBox {
        this.majorPermission.clear()
        this.majorPermission.addAll(majorPermission)
        this.onPermanentlyRejectCallback = onPermanentlyRejectCallback
        return this
    }

    /**
     * 设置权限名称转换
     * @param transformPermissionName 默认[DefaultPermissionInfo.transformPermissionName]
     */
    fun setPermissionNameConvert(transformPermissionName: (name: String) -> String): PermissionBox {
        this.transformPermissionName = transformPermissionName
        return this
    }

    /**
     * 设置权限的使用场景描述，在跳出系统权限弹窗的同时在屏幕顶部以弹窗形式展示描述内容
     * @param permissionPurpose 默认[DefaultPermissionInfo.permissionPurpose]
     */
    fun setPermissionPurpose(permissionPurpose: (name: String) -> String): PermissionBox {
        this.permissionPurpose = permissionPurpose
        return this
    }

    /**
     * 出现至少一个拒绝
     */
    fun setlLeastOneReject(onRejectCallback: ((grantedList: List<PermissionBean>, rejectList: List<PermissionBean>) -> Unit)? = null): PermissionBox {
        this.onRejectCallback = onRejectCallback
        return this
    }

    /**
     * 正常流程开始请求
     *
     * @param onAllGrantedCallback 当全部同意时回调
     */
    fun startRequest(onAllGrantedCallback: (() -> Unit)? = null) {
        this.onAllGrantedCallback = onAllGrantedCallback
        if (ui.isAllGrantedPermission(*(majorPermission + pNames).toSet().toTypedArray())) {
            onAllGrantedCallback?.invoke()
        } else {
            forceRequest()
        }
    }


    /**
     * 立即请求（一般为弹窗后再次调用）
     * 正常请求流请调用[startRequest]开启权限请求
     */
    private fun forceRequest() {
        val permissions = LinkedHashSet(majorPermission + pNames).toTypedArray()
        //系统内部会自动过滤同意过的权限
        PermissionFragment.reqPermission(
            ui,
            permissions,
            {
                //权限说明弹窗，随同请求权限一起展示
                postMainDelayedLifecycle(this.lifecycle, 100) {
                    purposeDialog?.dismiss()

                    val builder = StringBuilder()
                    permissions.forEach {
                        val st = permissionPurpose.invoke(it)
                        if (st.isNotEmpty() && !builder.contains(st)) {
                            if (builder.isNotEmpty()) {
                                builder.append("，")
                            }
                            builder.append(st)
                        }
                    }
                    if (builder.isEmpty()) return@postMainDelayedLifecycle
                    builder.append("。")

                    purposeDialog = AlertDialog.Builder(ui.requireActivity)
                        .setTitle("权限使用说明")
                        .setMessage(builder.toString())
                        .create()
                        .apply {
                            val layoutParams = this.window?.attributes
                            layoutParams?.gravity = Gravity.TOP
                            showWrapLifecycle(this.lifecycle)
                        }
                }
            }) { isReqSuccess, resultMap ->
            purposeDialog?.dismiss()

            val permanentlyRejectList = arrayListOf<PermissionBean>()
            val rejectList = arrayListOf<PermissionBean>()
            val grantedList = arrayListOf<PermissionBean>()
            var allGrant = true
            permissions.forEach { pName ->
                val permissionName = transformPermissionName.invoke(pName)
                "未配置${pName}提示名称".throwIfDebug { permissionName.isEmpty() }

                val permissionBean = if (resultMap[pName] == true) PermissionBean(pName, permissionName, true)
                else PermissionBean(pName, permissionName, false, ui.requireActivity.shouldShowRequestPermissionRationale(pName))

                if (permissionBean.accept) {
                    grantedList.add(permissionBean)
                } else {
                    if (!permissionBean.shouldShowRequest && onPermanentlyRejectCallback != null && majorPermission.contains(permissionBean.name)) {
                        permanentlyRejectList.add(permissionBean)
                    } else {
                        rejectList.add(permissionBean)
                    }
                    allGrant = false
                }
            }
            when {
                !isReqSuccess -> {
                    onRejectCallback?.invoke(grantedList, rejectList)
                }

                allGrant -> {
                    onAllGrantedCallback?.invoke()
                }

                permanentlyRejectList.isNotEmpty() -> {
                    onPermanentlyRejectCallback?.invoke(
                        permanentlyRejectList,
                        grantedList,
                        rejectList
                    )
                }

                else -> {
                    onRejectCallback?.invoke(grantedList, rejectList)
                }
            }
        }
    }
}
